/*
 * @Author: lll 1280388921@qq.com
 * @Date: 2025-05-05 14:14:22
 * @LastEditors: lll 1280388921@qq.com
 * @LastEditTime: 2025-05-07 15:16:47
 * @FilePath: /lesson37/mythread.cc
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
#include <iostream>
#include <pthread.h>
#include <unistd.h>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <vector>
#include "lockGuard.hpp"

using namespace std;

pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

#define NUM 4
class threadData
{
public:
    threadData(int num /*, pthread_mutex_t *lock*/)
    {
        tname = "thread-" + to_string(num);
        // lock_ = lock;
    }

public:
    string tname;
    // pthread_mutex_t *lock_;
};

int tickets = 1000;

// void *getTickets(void *args)
// {
//     threadData *td = static_cast<threadData *>(args);
//     const char *name = td->tname.c_str();
//     while (1)
//     {
//         // 线程对于锁的竞争能力可能会有不同！！
//         //  pthread_mutex_lock(td->lock_);
//         pthread_mutex_lock(&lock);
//         if (tickets > 0)
//         {
//             usleep(1000);
//             printf("%s get a ticket : %d\n", name, tickets);
//             tickets--;
//             // pthread_mutex_unlock(td->lock_);
//             pthread_mutex_unlock(&lock);
//         }
//         else
//         {
//             // pthread_mutex_unlock(td->lock_);
//             pthread_mutex_unlock(&lock);
//             break;
//         }
//         // 票没了执行break
//         // 如果锁在if/else之外，
//         // 那么执行break之后，就不会执行解锁代码了
//         //  pthread_mutex_unlock(td->lock_);//！！！
//         usleep(10);
//         // 先usleep一段时间，让其他的线程有机会被唤醒去申请锁
//         // 唤醒线程去申请锁的成本高于释放锁又立马申请锁的成本
//         // 所以释放锁又立马申请锁的速度更快

//         // 逻辑问题：
//         // 我们抢到了票，会有后续工作，不会立马抢下一张，所以用usleep模拟
//     }
//     printf("%s ... quit!\n", name);
//     return nullptr;
// }

void *getTickets(void *args)
{
    threadData *td = static_cast<threadData *>(args);
    const char *name = td->tname.c_str();
    while (1)
    {
        pthread_mutex_lock(&lock);
        pthread_mutex_lock(&lock);
        if (tickets > 0)
        {
            usleep(1000);
            printf("%s get a ticket : %d\n", name, tickets);
            tickets--;
            pthread_mutex_unlock(&lock);
        }
        else
        {
            pthread_mutex_unlock(&lock);
            break;
        }
        usleep(10);
    }
    printf("%s ... quit!\n", name);
    return nullptr;
}

// void *getTickets(void *args)
// {
//     threadData *td = static_cast<threadData *>(args);
//     const char *name = td->tname.c_str();
//     while (1)
//     {
//         {
//             LockGuard lockguard(&lock);
//             //构造加锁 析构解锁 RAII
//             if (tickets > 0)
//             {
//                 usleep(1000);
//                 printf("%s get a ticket : %d\n", name, tickets);
//                 tickets--;
//             }
//             else
//                 break;
//         }
//         usleep(10);
//     }
//     printf("%s ... quit!\n", name);
//     return nullptr;
// }

int main()
{
    // pthread_mutex_t lock; // 在main函数的栈上开辟的锁
    // pthread_mutex_init(&lock, nullptr);

    vector<pthread_t> tids;
    vector<threadData *> tds;
    for (int i = 1; i <= NUM; i++)
    {
        pthread_t tid;
        threadData *td = new threadData(i /*, &lock*/);
        tds.push_back(td);
        pthread_create(&tid, nullptr, getTickets, tds[i - 1]);
        tids.push_back(tid);
    }

    for (auto tid : tids)
    {
        pthread_join(tid, nullptr);
    }
    for (auto td : tds)
    {
        delete td;
    }
    // pthread_mutex_destroy(&lock);

    return 0;
}

// #define NUM 5

// // int*p;
// __thread int g_val=0;
// __thread unsigned int number=0;
// __thread int pid=0;
// // __thread threadData td;

// struct threadData
// {
//     string tname;
// };

// string toHex(pthread_t tid)
// {
//     char buffer[1024];
//     snprintf(buffer, sizeof(buffer), "0x%x", tid);
//     return buffer;
// }

// void InitThreadData(threadData *td, int i)
// {
//     td->tname = "thread-" + to_string(i);
// }

// void *threadRoutine(void *args)
// {
//     pthread_detach(pthread_self());
//     pid=getpid();
//     string tid=toHex(pthread_self());
//     int test_i=0;
//     threadData *td = static_cast<threadData *>(args);
//     int i = 0;
//     // if(td->tname=="thread-0")
//     // {
//     //     p=&test_i;
//     // }
//     while (i < 5)
//     {
//         cout<<"pid: "<<pid<<" ,tid: "<<tid<<endl;
//         // cout << "pid: " << getpid() << " ,tid: " << toHex(pthread_self())
//         // << " ,name: " << td->tname <<" ,g_val: "<<g_val<<" ,&g_val: "<<&g_val<< endl;
//         sleep(1);
//         // i++,test_i++;
//         i++,g_val++;
//     }
//     delete td;
//     return nullptr;
// }

// int main()
// {
//     vector<pthread_t> tids;
//     for (int i = 0; i < NUM; i++)
//     {
//         pthread_t tid;
//         threadData *td = new threadData;
//         // 使用堆空间 而且每次都是新的堆空间 堆空间是共享的 访问的是堆空间的不同位置
//         // 我们让一个线程访问对应的一个堆空间
//         InitThreadData(td, i);
//         pthread_create(&tid, nullptr, threadRoutine, td);
//         tids.push_back(tid);
//         // sleep(1);
//     }

//     // sleep(1);//确保赋值成功
//     // cout<<"main thread get a thread local value,val: "<<*p<<" ,&val: "<<p<<endl;

//     // sleep(1);
//     // for(auto i:tids)
//     // {
//     //     pthread_detach(i);
//     // }
//     for (int i = 0; i < NUM; i++)
//     {
//         int n=pthread_join(tids[i], nullptr);
//         printf("n = %d , who = 0x%x , why : %s\n",n,tids[i],strerror(n));
//     }

//     return 0;
// }